package locpris.swan.ac.uk;
import java.net.URL;
import java.util.ArrayList;

import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Geometry;
import com.jme.scene.Line;
import com.jme.scene.Node;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.Spatial.TextureCombineMode;
import com.jme.scene.shape.Box;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jme.app.BaseGame;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingSphere;
import com.jme.light.PointLight;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.LightState;
import com.jme.scene.state.MaterialState;



//create the plane for displaying nodes
public class CartesianPlane extends LocPriSMain{
 	/**
	 * If drawBehind is false, the grid is tested with the z-buffer, which means that
	 * only the visible parts of the grid will be seen and objects in front of the grid will
	 * hide it. 
	 */
	protected boolean drawBehind = false;
 	/**
	 * If drawAxis is true, Red, Green and Blue axis are drawn for the XYZ axis. Axis are
	 * never rotated, so they are always world axis, but they are translated to the grid
	 * center.
	 */
	protected boolean drawAxis = false;
 	// Center of the grid.
	protected final Vector3f center = new Vector3f();
	 // Space between grid lines.
	protected float quadrantLength = 5.0f;
	//Draw a bold line every given number of lines.
	protected int marker = 5;
 	/**
	 * Grid rotation. This is an Euler rotation (X,Y,Z). Values are multiplied by PI
	 * before being applied.
	 */
	protected final Vector3f rotatePi = new Vector3f();
	//the length of the plane div 2
	 //Grid extent. The extent is applied towards the positive and also negative sides of the grid.
	private float halfPlaneLength = 4.0f;
	private float halfPlaneWidth = 0;
	//set texture of sat photo
	private Boolean background = false;
	
	/**
	 * square plane
	 */
	public CartesianPlane(float planeSize, boolean background)
	{
		halfPlaneLength = planeSize / 2;
		if (background) { background = true; }
	}
	
	/**
	 * Rectangular plane
	 */
	public CartesianPlane(float planeLength, float planeWidth, boolean background)
	{
		halfPlaneLength = planeLength / 2;
		halfPlaneWidth = planeWidth /2;
	}	
	
	/**
	 * builds a 2D cartesian plane
	 * *
	 * @return the plane
	 */
	public Node build2DPlane(int floors) 
	{
		Node grid = new Node("grid");
		Node axis = new Node("axis");
		Node axisGrid = new Node("axisGrid");
 
		//Create Grid
		ArrayList<Vector3f> markerVertices = new ArrayList<Vector3f>();
		ArrayList<Vector3f> regularVertices = new ArrayList<Vector3f>();
		for (int j = 0; j < floors; j++) {		
		for (int i = 0; i * quadrantLength <= halfPlaneLength; i++) {
 
			if (i % marker > 0) {
				// Normal line
				regularVertices.add(new Vector3f(i * quadrantLength, j*10, -halfPlaneWidth));
				regularVertices.add(new Vector3f(i * quadrantLength, j*10, halfPlaneWidth));
				regularVertices.add(new Vector3f(-i * quadrantLength, j*10, -halfPlaneWidth));
				regularVertices.add(new Vector3f(-i * quadrantLength, j*10, halfPlaneWidth));
			} else {
				// Marker line
				if (i != 0) {
					markerVertices.add(new Vector3f(i * quadrantLength, j*10, -halfPlaneWidth));
					markerVertices.add(new Vector3f(i * quadrantLength, j*10, halfPlaneWidth));
					markerVertices.add(new Vector3f(-i * quadrantLength, j*10, -halfPlaneWidth));
					markerVertices.add(new Vector3f(-i * quadrantLength, j*10, halfPlaneWidth));
				}
			}
 
		}
		for (int i = 0; i * quadrantLength <= halfPlaneWidth; i++) {
			 
			if (i % marker > 0) {
				// Normal line
				regularVertices.add(new Vector3f(-halfPlaneLength, j*10, i * quadrantLength));
				regularVertices.add(new Vector3f(halfPlaneLength, j*10, i * quadrantLength));
				regularVertices.add(new Vector3f(-halfPlaneLength, j*10, -i * quadrantLength));
				regularVertices.add(new Vector3f(halfPlaneLength, j*10, -i * quadrantLength));
			} else {
				// Marker line
				markerVertices.add(new Vector3f(-halfPlaneLength, j*10, i * quadrantLength));
				markerVertices.add(new Vector3f(halfPlaneLength, j*10, i * quadrantLength));
				markerVertices.add(new Vector3f(-halfPlaneLength, j*10, -i * quadrantLength));
				markerVertices.add(new Vector3f(halfPlaneLength, j*10, -i * quadrantLength));
				if (i != 0) {
				}
			}
 
		}
		}
 
		Geometry regularGrid = new Line("regularLine", regularVertices.toArray(new Vector3f[] {}), null, null, null);
		regularGrid.getDefaultColor().set(ColorRGBA.darkGray);
		grid.attachChild(regularGrid);
		Geometry markerGrid = new Line("markerLine", markerVertices.toArray(new Vector3f[] {}), null, null, null);
		regularGrid.getDefaultColor().set(ColorRGBA.lightGray);
		grid.attachChild(markerGrid);
 		grid.getLocalRotation().fromAngles(FastMath.PI * rotatePi.x,FastMath.PI * rotatePi.y, FastMath.PI * rotatePi.z);
 		axisGrid.attachChild(grid);
 
		// Draws the three axis and colours them
 
		if (drawAxis) {
 
			Vector3f xAxis = new Vector3f(halfPlaneLength, 0, 0); //red
			Vector3f yAxis = new Vector3f(0, halfPlaneLength, 0); //green
			Vector3f zAxis = new Vector3f(0, 0, halfPlaneLength); //blue
 
			ColorRGBA[] red = new ColorRGBA[2];
			red[0] = new ColorRGBA(ColorRGBA.red);
			red[1] = new ColorRGBA(ColorRGBA.red);
 
			ColorRGBA[] green = new ColorRGBA[2];
			green[0] = new ColorRGBA(ColorRGBA.green);
			green[1] = new ColorRGBA(ColorRGBA.green);
 
			ColorRGBA[] blue = new ColorRGBA[2];
			blue[0] = new ColorRGBA(ColorRGBA.blue);
			blue[1] = new ColorRGBA(ColorRGBA.blue);
 
			Line lx = new Line("xAxis", new Vector3f[] { xAxis.negate(), xAxis },null, red, null);
			Line ly = new Line("yAxis", new Vector3f[] { yAxis.negate(), yAxis },null, green, null);
			Line lz = new Line("zAxis", new Vector3f[] { zAxis.negate(), zAxis },null, blue, null);
 
			lx.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
			lx.updateModelBound();
			ly.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
			ly.updateModelBound();
			lz.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
			lz.updateModelBound();
 
			axis.attachChild(lx);
			axis.attachChild(ly);
			axis.attachChild(lz);
 
			axisGrid.attachChild(axis);
 
		}
 
		// RenderStates for the whole grid and axis
 
		TextureState ts = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
		axisGrid.setTextureCombineMode(TextureCombineMode.Off);
		axisGrid.setRenderState(ts);
 
		ZBufferState zs = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
		//zs.setFunction(drawBehind ? TestFunction.Always	: TestFunction.LessThanOrEqualTo);
		zs.setWritable(false);
		zs.setEnabled(true);
		axisGrid.setRenderState(zs);
 
		axisGrid.setLightCombineMode(LightCombineMode.Off);
 
		axisGrid.updateRenderState();
 
		axisGrid.getLocalTranslation().set(center);
		axisGrid.updateGeometricState(0, true);
 
		axisGrid.lock();
		
		/**
		//background image
		Box backplane = new Box("background",new Vector3f(-halfPlaneLength,0,-halfPlaneLength), new Vector3f(halfPlaneLength,0,halfPlaneLength));
		//backplane.setDefaultColor(ColorRGBA.blue.clone());
		// Get a URL that points to the texture
		URL satphoto;
		satphoto = CartesianPlane.class.getClassLoader().getResource("locpris/swan/ac/uk/images/LocPriS/pic1.jpg");
 
		// Get a TextureState
		TextureState text1 = getDisplay().getRenderer().createTextureState();
		// Use the TextureManager to load a texture
		Texture t = TextureManager.loadTexture(satphoto,Texture.MinificationFilter.BilinearNearestMipMap,Texture.MagnificationFilter.Bilinear);
		// Assign the texture to the TextureState
		text1.setTexture(t);
		backplane.setRenderState(text1);
		
		axisGrid.attachChild(backplane);
		*/
		return axisGrid;
		
	}

	
	/**
	 * builds a 3D cartesian plane
	 * *
	 * @return the plane
	 */
	public Node build3DPlane() 
	{
		Node grid = new Node("grid");
		Node axis = new Node("axis");
		Node axisGrid = new Node("axisGrid");
 
		//Create Grid
		ArrayList<Vector3f> markerVertices = new ArrayList<Vector3f>();
		ArrayList<Vector3f> regularVertices = new ArrayList<Vector3f>();
		for (int i = 0; i * quadrantLength <= halfPlaneLength; i++) 
		{
 
			if (i % marker > 0) 
			{
				// Normal line
			//x-z lines
				
				for (int j=0; j * quadrantLength <= halfPlaneLength; j++)
				{
					regularVertices.add(new Vector3f(-halfPlaneLength+(j*quadrantLength), -halfPlaneLength, i * quadrantLength));	
					regularVertices.add(new Vector3f(-halfPlaneLength+(j*quadrantLength), halfPlaneLength, i * quadrantLength));
				
					regularVertices.add(new Vector3f(-halfPlaneLength+(j*quadrantLength), -halfPlaneLength, -i * quadrantLength));	
					regularVertices.add(new Vector3f(-halfPlaneLength+(j*quadrantLength), halfPlaneLength, -i * quadrantLength));	
				
					regularVertices.add(new Vector3f(-halfPlaneLength+(j*quadrantLength), i * quadrantLength, halfPlaneLength));	
					regularVertices.add(new Vector3f(-halfPlaneLength+(j*quadrantLength), i * quadrantLength, -halfPlaneLength));
				
					regularVertices.add(new Vector3f(-halfPlaneLength+(j*quadrantLength), -i * quadrantLength, halfPlaneLength));	
					regularVertices.add(new Vector3f(-halfPlaneLength+(j*quadrantLength), -i * quadrantLength, -halfPlaneLength));
					//other half of cube
					regularVertices.add(new Vector3f(halfPlaneLength-(j*quadrantLength), -halfPlaneLength, i * quadrantLength));	
					regularVertices.add(new Vector3f(halfPlaneLength-(j*quadrantLength), halfPlaneLength, i * quadrantLength));
				
					regularVertices.add(new Vector3f(halfPlaneLength-(j*quadrantLength), -halfPlaneLength, -i * quadrantLength));	
					regularVertices.add(new Vector3f(halfPlaneLength-(j*quadrantLength), halfPlaneLength, -i * quadrantLength));	
				
					regularVertices.add(new Vector3f(halfPlaneLength-(j*quadrantLength), i * quadrantLength, halfPlaneLength));	
					regularVertices.add(new Vector3f(halfPlaneLength-(j*quadrantLength), i * quadrantLength, -halfPlaneLength));
				
					regularVertices.add(new Vector3f(halfPlaneLength-(j*quadrantLength), -i * quadrantLength, halfPlaneLength));	
					regularVertices.add(new Vector3f(halfPlaneLength-(j*quadrantLength), -i * quadrantLength, -halfPlaneLength));
				}
				
							
			//x-y lines
				
				regularVertices.add(new Vector3f(-halfPlaneLength, 0, i * quadrantLength));
				regularVertices.add(new Vector3f(halfPlaneLength, 0, i * quadrantLength));
				
				regularVertices.add(new Vector3f(-halfPlaneLength, 0, -i * quadrantLength));
				regularVertices.add(new Vector3f(halfPlaneLength, 0, -i * quadrantLength));
				
				regularVertices.add(new Vector3f(i * quadrantLength, 0, -halfPlaneLength));
				regularVertices.add(new Vector3f(i * quadrantLength, 0, halfPlaneLength));
				
				regularVertices.add(new Vector3f(-i * quadrantLength, 0, -halfPlaneLength));
				regularVertices.add(new Vector3f(-i * quadrantLength, 0, halfPlaneLength));
				
				
			} else {
				// Marker line
				markerVertices.add(new Vector3f(-halfPlaneLength, 0, i * quadrantLength));
				markerVertices.add(new Vector3f(halfPlaneLength, 0, i * quadrantLength));
				markerVertices.add(new Vector3f(-halfPlaneLength, 0, -i * quadrantLength));
				markerVertices.add(new Vector3f(halfPlaneLength, 0, -i * quadrantLength));
				if (i != 0) {
					markerVertices.add(new Vector3f(i * quadrantLength, 0, -halfPlaneLength));
					markerVertices.add(new Vector3f(i * quadrantLength, 0, halfPlaneLength));
					markerVertices.add(new Vector3f(-i * quadrantLength, 0, -halfPlaneLength));
					markerVertices.add(new Vector3f(-i * quadrantLength, 0, halfPlaneLength));
				}
			}
 
		}
 
		Geometry regularGrid = new Line("regularLine", regularVertices.toArray(new Vector3f[] {}), null, null, null);
		regularGrid.getDefaultColor().set(ColorRGBA.darkGray);
		grid.attachChild(regularGrid);
		
		Geometry markerGrid = new Line("markerLine", markerVertices.toArray(new Vector3f[] {}), null, null, null);
		regularGrid.getDefaultColor().set(ColorRGBA.lightGray);
		grid.attachChild(markerGrid);
 		grid.getLocalRotation().fromAngles(FastMath.PI * rotatePi.x,FastMath.PI * rotatePi.y, FastMath.PI * rotatePi.z);
 		axisGrid.attachChild(grid);
 
		// Draws the three axis and colours them
 
		if (drawAxis) {
 
			Vector3f xAxis = new Vector3f(halfPlaneLength, 0, 0); //red
			Vector3f yAxis = new Vector3f(0, halfPlaneLength, 0); //green
			Vector3f zAxis = new Vector3f(0, 0, halfPlaneLength); //blue
 
			ColorRGBA[] red = new ColorRGBA[2];
			red[0] = new ColorRGBA(ColorRGBA.red);
			red[1] = new ColorRGBA(ColorRGBA.red);
 
			ColorRGBA[] green = new ColorRGBA[2];
			green[0] = new ColorRGBA(ColorRGBA.green);
			green[1] = new ColorRGBA(ColorRGBA.green);
 
			ColorRGBA[] blue = new ColorRGBA[2];
			blue[0] = new ColorRGBA(ColorRGBA.blue);
			blue[1] = new ColorRGBA(ColorRGBA.blue);
 
			Line lx = new Line("xAxis", new Vector3f[] { xAxis.negate(), xAxis },null, red, null);
			Line ly = new Line("yAxis", new Vector3f[] { yAxis.negate(), yAxis },null, green, null);
			Line lz = new Line("zAxis", new Vector3f[] { zAxis.negate(), zAxis },null, blue, null);
 
			lx.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
			lx.updateModelBound();
			ly.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
			ly.updateModelBound();
			lz.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
			lz.updateModelBound();
 
			axis.attachChild(lx);
			axis.attachChild(ly);
			axis.attachChild(lz);
 
			axisGrid.attachChild(axis);
 
		}
 
		// RenderStates for the whole grid and axis
 
		TextureState ts = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
		axisGrid.setTextureCombineMode(TextureCombineMode.Off);
		axisGrid.setRenderState(ts);
 
		ZBufferState zs = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
		//zs.setFunction(drawBehind ? TestFunction.Always	: TestFunction.LessThanOrEqualTo);
		zs.setWritable(false);
		zs.setEnabled(true);
		axisGrid.setRenderState(zs);
 
		axisGrid.setLightCombineMode(LightCombineMode.Off);
 
		axisGrid.updateRenderState();
 
		axisGrid.getLocalTranslation().set(center);
		axisGrid.updateGeometricState(0, true);
 
		axisGrid.lock();
 
		return axisGrid;
		
	}

	
	
}
